package com.kobeliu.service.impl;

import com.alibaba.druid.support.json.JSONUtils;
import com.github.pagehelper.PageInfo;
import com.google.gson.Gson;
import com.kobeliu.api.feign.SysParamFeign;
import com.kobeliu.api.feign.UsersMicroServiceFeign;
import com.kobeliu.base.BaseInfoProperties;
import com.kobeliu.exceptions.GraceException;
import com.kobeliu.pojo.ResumeEducation;
import com.kobeliu.pojo.ResumeExpect;
import com.kobeliu.pojo.ResumeWorkExp;
import com.kobeliu.pojo.bo.SearchResumesBO;
import com.kobeliu.pojo.eo.SearchResumesEO;
import com.kobeliu.pojo.mo.HrCollectResumeMO;
import com.kobeliu.pojo.vo.ResumeVO;
import com.kobeliu.pojo.vo.SearchResumesVO;
import com.kobeliu.pojo.vo.UsersVO;
import com.kobeliu.result.GraceJSONResult;
import com.kobeliu.result.ResponseStatusEnum;
import com.kobeliu.service.ResumeSearchService;
import com.kobeliu.service.ResumeService;
import com.kobeliu.utils.JsonUtils;
import com.kobeliu.utils.LocalDateUtils;
import com.kobeliu.utils.PagedGridResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
//import org.apache.zookeeper.ZooDefs;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.IdsQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ResumeSearchServiceImpl extends BaseInfoProperties implements ResumeSearchService {

    @Autowired
    private ResumeService resumeService;

    @Autowired
    private ElasticsearchRestTemplate esTemplate;

    @Autowired
    private UsersMicroServiceFeign userFeign;
    @Autowired
    private SysParamFeign sysParamFeign;


    @Override
    public void transformAndFlush2Es(String userId) {

        String today = LocalDateUtils.getLocalDateStr();
        //redis中读
        String countsStr = redis.get(USER_ALREADY_REFRESHED_COUNTS+":"+userId+":"+today);
        Integer maxCounts = null;

        if(StringUtils.isNotBlank(countsStr)){
            maxCounts = Integer.parseInt(countsStr);
        }else {
            //查询最大刷新次数
            maxCounts = sysParamFeign.paramsByFeign();
        }
        if(maxCounts == null)
            maxCounts = 3;
        if(maxCounts<1){
            //当天刷新次数不够了
            GraceException.display(ResponseStatusEnum.RESUME_MAX_LIMIT_ERROR);
        }
        if(StringUtils.isBlank(userId)){
            GraceException.display(ResponseStatusEnum.USER_STATUS_ERROR);
        }

        //声明es对象
        SearchResumesEO eo = new SearchResumesEO();

        //根据userID去拿resume的数据
        ResumeVO vo = resumeService.getByUserId(userId);

        if(vo == null){
            GraceException.display(ResponseStatusEnum.RESUME_IS_NOT_EXIST);
        }
        //拿取用户信息
        UsersVO userInfo = this.getUserInfo(userId);

        eo.setNickname(userInfo.getNickname());
        eo.setUserId(userId);
     //   eo.setCity(userInfo.getCity());
        eo.setSex(userInfo.getSex());
        eo.setBirthday(LocalDateUtils.format(userInfo.getBirthday(),LocalDateUtils.DATE_PATTERN));
        // 当前时间 - 生日
        Long age = LocalDateUtils.getChronoUnitBetween(userInfo.getBirthday(), LocalDate.now(), ChronoUnit.YEARS,false);
        eo.setAge(age.intValue()+1);

        eo.setResumeId(vo.getId());
        eo.setAdvantage(vo.getAdvantage());
        eo.setAdvantageHtml(vo.getAdvantageHtml());
        eo.setCredentials(vo.getCredentials());
        eo.setSkills(vo.getSkills());
        eo.setJobStatus(vo.getStatus());
        eo.setFace(userInfo.getFace());

        //es时间与db保持一致
        eo.setRefreshTime(LocalDateUtils.format(vo.getRefreshTime(),LocalDateUtils.DATETIME_PATTERN));

        // 计算工作年限
        Long workTime = LocalDateUtils.getChronoUnitBetween(userInfo.getStartWorkDate(), LocalDate.now(), ChronoUnit.YEARS,false);
        eo.setWorkYears(workTime.intValue());

        //就业经历放入es
        List<ResumeWorkExp> workExpList = vo.getWorkExpList();
        //lambda 流处理拿取最大值
        Optional<ResumeWorkExp> lastWork = workExpList.stream().max(Comparator.comparing(ResumeWorkExp::getBeginDate));
        //最新的工作经历
        ResumeWorkExp resumeWorkExp = lastWork.get();
        eo.setCompanyName(resumeWorkExp.getCompanyName());
        eo.setPosition(resumeWorkExp.getPosition());
        eo.setIndustry(resumeWorkExp.getIndustry());

        //最近一次教育经历放入es
        //就业经历放入es
        List<ResumeEducation> eduList = vo.getEducationList();
        //lambda 流处理拿取最大值
        Optional<ResumeEducation> lastEdu = eduList.stream().max(Comparator.comparing(ResumeEducation::getBeginDate));
        ResumeEducation resumeEducation = lastEdu.get();
        eo.setSchool(resumeEducation.getSchool());
        eo.setMajor(resumeEducation.getMajor());
        eo.setEducation(resumeEducation.getEducation());

        List<ResumeExpect> myResumeExpectList = resumeService.getMyResumeExpectList(vo.getId(), userId);
        // 一个resumeId有多个期望，所以每个期望生成一条数据放入es
        for (ResumeExpect exp:myResumeExpectList){
            eo.setResumeExpectId(exp.getId());
            eo.setJobType(exp.getJobName());
            eo.setCity(exp.getCity());
            eo.setBeginSalary(exp.getBeginSalary());
            eo.setEndSalary(exp.getEndSalary());

            IndexQuery iq = new IndexQueryBuilder().withObject(eo).build();
            esTemplate.index(iq,IndexCoordinates.of("resume_result"));

            maxCounts--;
            redis.set(USER_ALREADY_REFRESHED_COUNTS+":"+userId+":"+today,String.valueOf(maxCounts));
        }
    }

    @Override
    public PagedGridResult searchResumesByEs(SearchResumesBO searchResumesBO, Integer page, Integer limit) {

        String basicTitle = searchResumesBO.getBasicTitle();
        String jobType = searchResumesBO.getJobType();
        Integer beginAge = searchResumesBO.getBeginAge();
        Integer endAge = searchResumesBO.getEndAge();
        Integer sex = searchResumesBO.getSex();
        Integer activeTimes = searchResumesBO.getActiveTimes();
        Integer beginWorkExpYears = searchResumesBO.getBeginWorkExpYears();
        Integer endWorkExpYears = searchResumesBO.getEndWorkExpYears();
        String edu = searchResumesBO.getEdu();
//        List<String> eduList = searchResumesBO.getEduList();
        Integer beginSalary = searchResumesBO.getBeginSalary();
        Integer endSalary = searchResumesBO.getEndSalary();
        String jobStatus = searchResumesBO.getJobStatus();

        //分页
        Pageable pageable = PageRequest.of(--page,limit);

        //用于区分是否需要match_all 若包含条件则条件搜索
        boolean conditionAdded = false;

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //匹配默认搜索框
        if(StringUtils.isNotBlank(basicTitle)){
            //匹配默认搜索框
            boolQueryBuilder.must(QueryBuilders.boolQuery()
                    .should(QueryBuilders.matchQuery("nickname",basicTitle))
                    .should(QueryBuilders.matchQuery("advantage",basicTitle))
                    .should(QueryBuilders.matchQuery("credentials",basicTitle))
                    .should(QueryBuilders.matchQuery("skills",basicTitle))
                    );
            conditionAdded = true;
        }
        //匹配职位类型
        if(StringUtils.isNotBlank(jobType)){
            boolQueryBuilder.must(QueryBuilders.matchQuery("jobType",jobType));
            conditionAdded = true;
        }
        //匹配年龄
        if(beginAge > 0 && endAge > 0){
            // 数值类 区间查询
            boolQueryBuilder.must(QueryBuilders.rangeQuery("age")
                    .gte(beginAge)
                    .lte(endAge));
            conditionAdded = true;
        }
        //性别
        if(sex != null && sex !=-1){
            //精确匹配
            boolQueryBuilder.must(QueryBuilders.termQuery("sex",sex));
            conditionAdded = true;
        }
        //匹配活跃度 当前时间 - 活跃度 = 临界时间点 若刷新时间比它新 说明符合条件
        if(activeTimes != null && activeTimes >0){

            LocalDateTime temp = LocalDateUtils.minus(LocalDateTime.now(),
                                                        activeTimes, ChronoUnit.SECONDS);
            String timePoint = LocalDateUtils.format(temp,LocalDateUtils.DATETIME_PATTERN);

            //es进行比对
            boolQueryBuilder.must(QueryBuilders.rangeQuery("refreshTime")
                    .gte(timePoint));
            conditionAdded = true;
        }
        //匹配工作年限
        if(beginWorkExpYears>=0 && endWorkExpYears > 0){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("workYears")
                    .gte(beginWorkExpYears)
                    .lte(endWorkExpYears));
            conditionAdded = true;
        }
        //匹配学历
        if(StringUtils.isNotBlank(edu)){
            //只查一个edu字段，只查一个 不多叉
            boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("education",edu));
        }
        //匹配薪资
        if(beginSalary>0 && endSalary>0){
            conditionAdded=true;

            BoolQueryBuilder bool1 = QueryBuilders.boolQuery()
                    .must(QueryBuilders.rangeQuery("beginSalary").lte(beginSalary))
                    .must(QueryBuilders.rangeQuery("endSalary").gte(beginSalary)
                    );
            //OR
            BoolQueryBuilder bool2 = QueryBuilders.boolQuery()
                    .must(QueryBuilders.rangeQuery("beginSalary").lte(endSalary))
                    .must(QueryBuilders.rangeQuery("endSalary").gte(endSalary)
                    );
            boolQueryBuilder.must(QueryBuilders.boolQuery()
                    .should(bool1)
                    .should(bool2)
                    );

        }
        //匹配求职状态
        if(StringUtils.isNotBlank(jobStatus)){
            conditionAdded = true;
            boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("jobStatus",jobStatus));
        }


        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        if(conditionAdded){
            //走条件查询
            builder.withQuery(boolQueryBuilder);
        }else{
            //走match_all
            builder.withQuery(QueryBuilders.matchAllQuery());
        }

        Query query = builder.withPageable(pageable).build();

        SearchHits<SearchResumesEO> hits = esTemplate.search(query, SearchResumesEO.class);
        List<SearchResumesEO> eos = hits.stream().map(obj -> {
            SearchResumesEO eo = obj.getContent();
            return eo;
        }).collect(Collectors.toList());

        PagedGridResult pagedGridResult = new PagedGridResult();
        pagedGridResult.setRows(eos);
        pagedGridResult.setPage(page+1);

        return pagedGridResult;

    }

    @Override
    public ResumeVO getByUserId(String userId) {
        return new ResumeVO();
    }

    @Override
    public List<SearchResumesEO> listResumeEOs(List<String> ids) {
        List<SearchResumesEO> eos = new ArrayList<>();
        if(ids.size()==0){
            return eos;
        }
        IdsQueryBuilder queryBuilder = new IdsQueryBuilder();
        for(String id:ids){
            queryBuilder.addIds(id);
        }

        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.should(queryBuilder);

        Query query = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .build();

        SearchHits<SearchResumesEO> eoSearchHits = esTemplate.search(query, SearchResumesEO.class);

        eos = eoSearchHits.stream()
                .map(SearchHit::getContent)
                .collect(Collectors.toList());

        return eos;

    }

    @Override
    public List<SearchResumesEO> pagedReadResumeRecordList(List<String> ids) {

        List<SearchResumesEO> eos = new ArrayList<>();
        if(ids.size()==0){
            return eos;
        }

        IdsQueryBuilder idsQueryBuilder = new IdsQueryBuilder();

        for(String id:ids){
            idsQueryBuilder.queryName("resume_expect_id").addIds(id);
        }

        BoolQueryBuilder builder = new BoolQueryBuilder();
        builder.should(idsQueryBuilder);

        Query query = new NativeSearchQueryBuilder().withQuery(builder).build();

        SearchHits<SearchResumesEO> search = esTemplate.search(query, SearchResumesEO.class);

        eos = search.stream().map(SearchHit::getContent).collect(Collectors.toList());

        return eos;
    }

    private UsersVO getUserInfo(String userId){

//        log.info("======================================");
//        log.info("userId:{}",userId);
//        log.info("======================================");
        //远程feign拿取用户信息
        GraceJSONResult info = userFeign.getInfo(userId);
        if(info.getStatus() == 200){
            String jsonStr = info.getData().toString();
//            return JsonUtils.jsonToPojo(jsonStr,UsersVO.class);
//            String jsonStr = new Gson().toJson(info.getData());
            return new Gson().fromJson(jsonStr,UsersVO.class);
        }


        GraceException.display(ResponseStatusEnum.RESUME_IS_NOT_EXIST);
        return new UsersVO();
    }


    //    @Override
//    public PagedGridResult searchResumes(SearchResumesEO searchResumesEO, Integer page, Integer limit) {
//        return null;
//    }
}
